﻿namespace UnityEditor
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using UnityEngine;

    [StructLayout(LayoutKind.Sequential)]
    public class Editor : ScriptableObject
    {
        private const float kImageSectionWidth = 44f;
        private const int kPreviewLabelHeight = 12;
        private const int kPreviewMinSize = 0x37;
        private const int kGridTargetCount = 0x19;
        private const int kGridSpacing = 10;
        internal const float kLineHeight = 16f;
        private static Styles s_Styles;
        private UnityEngine.Object[] m_Targets;
        private int m_IsDirty;
        private int m_ReferenceTargetIndex;
        internal SerializedObject m_SerializedObject;
        private OptimizedGUIBlock m_OptimizedBlock;
        internal InspectorMode m_InspectorMode;
        internal bool hideInspector;
        internal static bool m_AllowMultiObjectAccess = true;
        internal bool DoDrawDefaultInspector()
        {
            EditorGUI.BeginChangeCheck();
            this.serializedObject.Update();
            SerializedProperty iterator = this.serializedObject.GetIterator();
            for (bool flag = true; iterator.NextVisible(flag); flag = false)
            {
                EditorGUILayout.PropertyField(iterator, true, new GUILayoutOption[0]);
            }
            this.serializedObject.ApplyModifiedProperties();
            return EditorGUI.EndChangeCheck();
        }

        internal virtual void OnHeaderGUI()
        {
            DrawHeaderGUI(this, this.targetName);
        }

        internal virtual void OnHeaderControlsGUI()
        {
            GUILayoutUtility.GetRect(10f, 10f, 16f, 16f, EditorStyles.layerMaskField);
            GUILayout.FlexibleSpace();
            bool flag = true;
            if (!(this is AssetImporterInspector))
            {
                if (!AssetDatabase.IsMainAsset(this.targets[0]))
                {
                    flag = false;
                }
                AssetImporter atPath = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(this.targets[0]));
                if ((atPath != null) && (atPath.GetType() != typeof(AssetImporter)))
                {
                    flag = false;
                }
            }
            if (flag && GUILayout.Button("Open", EditorStyles.miniButton, new GUILayoutOption[0]))
            {
                if (this is AssetImporterInspector)
                {
                    AssetDatabase.OpenAsset((this as AssetImporterInspector).assetEditor.targets);
                }
                else
                {
                    AssetDatabase.OpenAsset(this.targets);
                }
                GUIUtility.ExitGUI();
            }
        }

        internal virtual void OnHeaderIconGUI(Rect iconRect)
        {
            if (s_Styles == null)
            {
                s_Styles = new Styles();
            }
            Texture2D image = null;
            if (!this.HasPreviewGUI())
            {
                bool flag = AssetPreview.IsLoadingAssetPreview(this.target.GetInstanceID());
                image = AssetPreview.GetAssetPreview(this.target);
                if (image == null)
                {
                    if (flag)
                    {
                        this.Repaint();
                    }
                    image = AssetPreview.GetMiniThumbnail(this.target);
                }
            }
            if (this.HasPreviewGUI())
            {
                this.OnPreviewGUI(iconRect, s_Styles.inspectorBigInner);
            }
            else if (image != null)
            {
                GUI.Label(iconRect, image, s_Styles.centerStyle);
            }
        }

        internal virtual void OnHeaderTitleGUI(Rect titleRect, string header)
        {
            titleRect.yMin -= 2f;
            titleRect.yMax += 2f;
            GUI.Label(titleRect, header, EditorStyles.largeLabel);
        }

        internal virtual void DrawHeaderHelpAndSettingsGUI(Rect r)
        {
            if (EditorGUI.s_HelpIcon == null)
            {
                EditorGUI.s_HelpIcon = EditorGUIUtility.IconContent("_Help");
                EditorGUI.s_TitleSettingsIcon = EditorGUIUtility.IconContent("_Popup");
            }
            UnityEngine.Object target = this.target;
            AssetImporterInspector inspector = this as AssetImporterInspector;
            if ((inspector != null) && !Help.HasHelpForObject(target))
            {
                target = inspector.assetEditor.target;
            }
            EditorGUI.HelpIconButton(new Rect(r.width - 36f, r.y + 5f, 14f, 14f), target);
            EditorGUI.BeginDisabledGroup(!this.IsEnabled());
            Rect position = new Rect(r.width - 18f, r.y + 5f, 14f, 14f);
            if (EditorGUI.ButtonMouseDown(position, EditorGUI.s_TitleSettingsIcon, FocusType.Native, EditorStyles.inspectorTitlebarText))
            {
                EditorUtility.DisplayObjectContextMenu(position, this.targets, 0);
            }
            EditorGUI.EndDisabledGroup();
        }

        internal static Rect DrawHeaderGUI(Editor editor, string header)
        {
            if (s_Styles == null)
            {
                s_Styles = new Styles();
            }
            GUILayout.BeginHorizontal(s_Styles.inspectorBig, new GUILayoutOption[0]);
            GUILayout.Space(38f);
            GUILayout.BeginVertical(new GUILayoutOption[0]);
            GUILayout.Space(19f);
            GUILayout.BeginHorizontal(new GUILayoutOption[0]);
            if (editor != null)
            {
                editor.OnHeaderControlsGUI();
            }
            else
            {
                EditorGUILayout.GetControlRect(new GUILayoutOption[0]);
            }
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();
            GUILayout.EndHorizontal();
            Rect lastRect = GUILayoutUtility.GetLastRect();
            float width = lastRect.width;
            Rect iconRect = new Rect(6f, lastRect.y + 6f, 32f, 32f);
            if (editor != null)
            {
                editor.OnHeaderIconGUI(iconRect);
            }
            else
            {
                GUI.Label(iconRect, AssetPreview.GetMiniTypeThumbnail(typeof(UnityEngine.Object)), s_Styles.centerStyle);
            }
            Rect titleRect = new Rect(44f, lastRect.y + 6f, ((width - 44f) - 38f) - 4f, 16f);
            if (editor != null)
            {
                editor.OnHeaderTitleGUI(titleRect, header);
            }
            else
            {
                GUI.Label(titleRect, header, EditorStyles.largeLabel);
            }
            if (editor != null)
            {
                editor.DrawHeaderHelpAndSettingsGUI(lastRect);
            }
            Event current = Event.current;
            if ((((editor != null) && !editor.IsEnabled()) && ((current.type == EventType.MouseDown) && (current.button == 1))) && lastRect.Contains(current.mousePosition))
            {
                EditorUtility.DisplayObjectContextMenu(new Rect(current.mousePosition.x, current.mousePosition.y, 0f, 0f), editor.targets, 0);
                current.Use();
            }
            return lastRect;
        }

        internal virtual void DrawPreview(Rect previewPosition)
        {
            if (s_Styles == null)
            {
                s_Styles = new Styles();
            }
            string text = string.Empty;
            Event current = Event.current;
            if (this.targets.Length > 1)
            {
                Rect rect = new RectOffset(0x10, 0x10, 20, 0x19).Remove(previewPosition);
                int num = Mathf.Max(1, Mathf.FloorToInt((rect.height + 10f) / 77f));
                int num2 = Mathf.Max(1, Mathf.FloorToInt((rect.width + 10f) / 65f));
                int num3 = num * num2;
                int minimumNr = Mathf.Min(this.targets.Length, 0x19);
                bool flag = true;
                int[] numArray = new int[] { num2, num };
                if (minimumNr < num3)
                {
                    numArray = this.GetGridDivision(rect, minimumNr, 12);
                    flag = false;
                }
                int num5 = Mathf.Min(numArray[0] * numArray[1], this.targets.Length);
                rect.width += 10f;
                rect.height += 10f;
                Vector2 vector = new Vector2((float) Mathf.FloorToInt((rect.width / ((float) numArray[0])) - 10f), (float) Mathf.FloorToInt((rect.height / ((float) numArray[1])) - 10f));
                float a = Mathf.Min(vector.x, vector.y - 12f);
                if (flag)
                {
                    a = Mathf.Min(a, 55f);
                }
                bool flag2 = (((current.type == EventType.MouseDown) && (current.button == 0)) && (current.clickCount == 2)) && previewPosition.Contains(current.mousePosition);
                int referenceTargetIndex = this.referenceTargetIndex;
                for (int i = 0; i < num5; i++)
                {
                    this.referenceTargetIndex = i;
                    Rect position = new Rect(rect.x + (((i % numArray[0]) * rect.width) / ((float) numArray[0])), rect.y + (((i / numArray[0]) * rect.height) / ((float) numArray[1])), vector.x, vector.y);
                    if (flag2 && position.Contains(Event.current.mousePosition))
                    {
                        Selection.objects = new UnityEngine.Object[] { this.target };
                    }
                    position.height -= 12f;
                    Rect rect3 = new Rect(position.x + ((position.width - a) * 0.5f), position.y + ((position.height - a) * 0.5f), a, a);
                    GUI.BeginGroup(rect3);
                    m_AllowMultiObjectAccess = false;
                    this.OnInteractivePreviewGUI(new Rect(0f, 0f, a, a), s_Styles.preBackgroundSolid);
                    m_AllowMultiObjectAccess = true;
                    GUI.EndGroup();
                    position.y = rect3.yMax;
                    position.height = 16f;
                    GUI.Label(position, this.target.name, s_Styles.previewMiniLabel);
                }
                this.referenceTargetIndex = referenceTargetIndex;
                if (Event.current.type == EventType.Repaint)
                {
                    object[] objArray2 = new object[] { "Previewing ", num5, " of ", this.targets.Length, " Objects" };
                    text = string.Concat(objArray2);
                }
            }
            else
            {
                m_AllowMultiObjectAccess = !this.canEditMultipleObjects;
                this.OnInteractivePreviewGUI(previewPosition, s_Styles.preBackground);
                m_AllowMultiObjectAccess = true;
                if (Event.current.type == EventType.Repaint)
                {
                    text = this.GetInfoString();
                    if (text != string.Empty)
                    {
                        text = text.Replace("\n", "   ");
                        text = this.target.name + "\n" + text;
                    }
                }
            }
            if ((Event.current.type == EventType.Repaint) && (text != string.Empty))
            {
                EditorGUI.DropShadowLabel(new Rect(previewPosition.x, previewPosition.yMax - 50f, previewPosition.width, 45f), text);
            }
        }

        private int[] GetGridDivision(Rect rect, int minimumNr, int labelHeight)
        {
            float num = Mathf.Sqrt((rect.width * rect.height) / ((float) minimumNr));
            int num2 = Mathf.FloorToInt(rect.width / num);
            int num3 = Mathf.FloorToInt(rect.height / (num + labelHeight));
            while ((num2 * num3) < minimumNr)
            {
                float num4 = this.AbsRatioDiff(((float) (num2 + 1)) / rect.width, ((float) num3) / (rect.height - (num3 * labelHeight)));
                float num5 = this.AbsRatioDiff(((float) num2) / rect.width, ((float) (num3 + 1)) / (rect.height - ((num3 + 1) * labelHeight)));
                if (num4 < num5)
                {
                    num2++;
                    if ((num2 * num3) > minimumNr)
                    {
                        num3 = Mathf.CeilToInt(((float) minimumNr) / ((float) num2));
                    }
                }
                else
                {
                    num3++;
                    if ((num2 * num3) > minimumNr)
                    {
                        num2 = Mathf.CeilToInt(((float) minimumNr) / ((float) num3));
                    }
                }
            }
            return new int[] { num2, num3 };
        }

        private float AbsRatioDiff(float x, float y)
        {
            return Mathf.Max((float) (x / y), (float) (y / x));
        }

        internal virtual bool IsEnabled()
        {
            foreach (UnityEngine.Object obj2 in this.targets)
            {
                if ((obj2.hideFlags & HideFlags.NotEditable) != 0)
                {
                    return false;
                }
                if (!AssetDatabase.IsOpenForEdit(obj2))
                {
                    return false;
                }
            }
            return true;
        }

        internal bool IsOpenForEdit()
        {
            string str;
            return this.IsOpenForEdit(out str);
        }

        internal bool IsOpenForEdit(out string message)
        {
            message = string.Empty;
            foreach (UnityEngine.Object obj2 in this.targets)
            {
                if (!AssetDatabase.IsOpenForEdit(obj2, out message))
                {
                    return false;
                }
            }
            return true;
        }

        internal bool canEditMultipleObjects
        {
            get
            {
                return (base.GetType().GetCustomAttributes(typeof(CanEditMultipleObjects), false).Length > 0);
            }
        }
        public static Editor CreateEditor(UnityEngine.Object obj)
        {
            System.Type editorType = null;
            return CreateEditor(obj, editorType);
        }

        public static Editor CreateEditor(UnityEngine.Object obj, System.Type editorType)
        {
            UnityEngine.Object[] objects = new UnityEngine.Object[] { obj };
            return CreateEditor(objects, editorType);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern Editor CreateEditor(UnityEngine.Object[] objects, System.Type editorType);
        public static Editor CreateEditor(UnityEngine.Object[] objects)
        {
            System.Type editorType = null;
            return CreateEditor(objects, editorType);
        }

        public UnityEngine.Object target
        {
            get
            {
                return this.m_Targets[this.referenceTargetIndex];
            }
        }
        public UnityEngine.Object[] targets
        {
            get
            {
                if (!m_AllowMultiObjectAccess)
                {
                    Debug.LogError("The targets array should not be used inside OnSceneGUI or OnPreviewGUI. Use the single target property instead.");
                }
                return this.m_Targets;
            }
        }
        internal virtual int referenceTargetIndex
        {
            get
            {
                return Mathf.Clamp(this.m_ReferenceTargetIndex, 0, this.m_Targets.Length - 1);
            }
            set
            {
                this.m_ReferenceTargetIndex = (Math.Abs((int) (value * this.m_Targets.Length)) + value) % this.m_Targets.Length;
            }
        }
        internal virtual string targetName
        {
            get
            {
                if ((this.m_Targets.Length == 1) || !m_AllowMultiObjectAccess)
                {
                    return this.target.name;
                }
                object[] objArray1 = new object[] { this.m_Targets.Length, " ", ObjectNames.NicifyVariableName(ObjectNames.GetClassName(this.target)), "s" };
                return string.Concat(objArray1);
            }
        }
        public SerializedObject serializedObject
        {
            get
            {
                if (!m_AllowMultiObjectAccess)
                {
                    Debug.LogError("The serializedObject should not be used inside OnSceneGUI or OnPreviewGUI. Use the target property directly instead.");
                }
                return this.GetSerializedObjectInternal();
            }
        }
        internal virtual SerializedObject GetSerializedObjectInternal()
        {
            if (this.m_SerializedObject == null)
            {
                this.m_SerializedObject = new SerializedObject(this.targets);
            }
            return this.m_SerializedObject;
        }

        private void CleanupPropertyEditor()
        {
            if (this.m_OptimizedBlock != null)
            {
                this.m_OptimizedBlock.Dispose();
                this.m_OptimizedBlock = null;
            }
            if (this.m_SerializedObject != null)
            {
                this.m_SerializedObject.Dispose();
                this.m_SerializedObject = null;
            }
        }

        private void OnDisableINTERNAL()
        {
            this.CleanupPropertyEditor();
        }

        internal void OnForceReloadInspector()
        {
            if (this.m_SerializedObject != null)
            {
                this.m_SerializedObject.SetIsDifferentCacheDirty();
            }
        }

        internal bool GetOptimizedGUIBlockImplementation(bool isDirty, bool isVisible, out OptimizedGUIBlock block, out float height)
        {
            if (this.m_OptimizedBlock == null)
            {
                this.m_OptimizedBlock = new OptimizedGUIBlock();
            }
            block = this.m_OptimizedBlock;
            if (!isVisible)
            {
                height = 0f;
                return true;
            }
            if (this.m_SerializedObject == null)
            {
                this.m_SerializedObject = new SerializedObject(this.targets);
            }
            else
            {
                this.m_SerializedObject.Update();
            }
            this.m_SerializedObject.inspectorMode = this.m_InspectorMode;
            this.m_SerializedObject.animationMode = AnimationUtility.InAnimationMode();
            SerializedProperty iterator = this.m_SerializedObject.GetIterator();
            height = 0f;
            for (bool flag = true; iterator.NextVisible(flag); flag = false)
            {
                height += EditorGUI.GetPropertyHeight(iterator, null, true);
            }
            return true;
        }

        internal bool OptimizedInspectorGUIImplementation(Rect contentRect)
        {
            SerializedProperty iterator = this.m_SerializedObject.GetIterator();
            EditorGUIUtility.SetIconSize(new Vector2(16f, 16f));
            bool enterChildren = true;
            bool enabled = GUI.enabled;
            while (iterator.NextVisible(enterChildren))
            {
                contentRect.height = EditorGUI.GetPropertyHeight(iterator, null, false);
                EditorGUI.indentLevel = iterator.depth + 1;
                enterChildren = EditorGUI.PropertyField(contentRect, iterator);
                contentRect.y += contentRect.height;
            }
            GUI.enabled = enabled;
            EditorGUIUtility.SetIconSize(Vector2.zero);
            return this.m_SerializedObject.ApplyModifiedProperties();
        }

        protected internal static void DrawPropertiesExcluding(SerializedObject obj, params string[] propertyToExclude)
        {
            SerializedProperty iterator = obj.GetIterator();
            int index = 0;
            bool enterChildren = true;
            while (iterator.NextVisible(enterChildren))
            {
                enterChildren = false;
                if ((index < propertyToExclude.Length) && (iterator.name == propertyToExclude[index]))
                {
                    index++;
                }
                else
                {
                    EditorGUILayout.PropertyField(iterator, true, new GUILayoutOption[0]);
                }
            }
        }

        public bool DrawDefaultInspector()
        {
            return this.DoDrawDefaultInspector();
        }

        public virtual void OnInspectorGUI()
        {
            this.DrawDefaultInspector();
        }

        internal void InternalSetTargets(UnityEngine.Object[] t)
        {
            this.m_Targets = t;
        }

        internal void InternalSetHidden(bool hidden)
        {
            this.hideInspector = hidden;
        }

        internal virtual bool GetOptimizedGUIBlock(bool isDirty, bool isVisible, out OptimizedGUIBlock block, out float height)
        {
            block = null;
            height = -1f;
            return false;
        }

        internal virtual bool OnOptimizedInspectorGUI(Rect contentRect)
        {
            Debug.LogError("Not supported");
            return false;
        }

        internal bool isInspectorDirty
        {
            get
            {
                return (this.m_IsDirty != 0);
            }
            set
            {
                this.m_IsDirty = !value ? 0 : 1;
            }
        }
        public void Repaint()
        {
            InspectorWindow.RepaintAllInspectors();
        }

        public virtual bool HasPreviewGUI()
        {
            return false;
        }

        public virtual GUIContent GetPreviewTitle()
        {
            return null;
        }

        public virtual Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height)
        {
            return null;
        }

        public virtual void OnPreviewGUI(Rect r, GUIStyle background)
        {
            if (Event.current.type == EventType.Repaint)
            {
                background.Draw(r, false, false, false, false);
            }
        }

        public virtual void OnInteractivePreviewGUI(Rect r, GUIStyle background)
        {
            this.OnPreviewGUI(r, background);
        }

        public virtual void OnPreviewSettings()
        {
        }

        public virtual string GetInfoString()
        {
            return string.Empty;
        }

        internal virtual void OnAssetStoreInspectorGUI()
        {
        }
        private class Styles
        {
            public GUIStyle centerStyle = new GUIStyle();
            public GUIStyle inspectorBig = new GUIStyle(EditorStyles.inspectorBig);
            public GUIStyle inspectorBigInner = new GUIStyle("IN BigTitle inner");
            public GUIStyle preBackground = "preBackground";
            public GUIStyle preBackgroundSolid = new GUIStyle("preBackground");
            public GUIStyle previewMiniLabel = new GUIStyle(EditorStyles.whiteMiniLabel);

            public Styles()
            {
                this.centerStyle.alignment = TextAnchor.MiddleCenter;
                this.preBackgroundSolid.overflow = this.preBackgroundSolid.border;
                this.previewMiniLabel.alignment = TextAnchor.UpperCenter;
                RectOffset padding = this.inspectorBig.padding;
                padding.bottom--;
            }
        }
    }
}

